#include "QuadBarreledShotgunRacruvido.h"
#include <GL/glu.h>
#include "gllib/Objects.h"
#include "src/mathlib/Matrix4.h"
#include <cmath>

#define QBSG_CANO_RAIO      0.125
#define QBSG_CANO_ALTURA    1.8
#define QBSG_CANO_PRECISAO  10.0

void QuadBarreledShotgunRacruvido::draw_cano(float x)
{
    double cano_raio = QBSG_CANO_RAIO;
    double cano_altura = 2.8;
    double cano_precisao = QBSG_CANO_PRECISAO;
    double cano_traseira_escala = 0.6;
    // Cano:
    glPushMatrix();
        translationMatrix(Vector3(x,0.0,(cano_altura/2.0))).applyGL();
        rotationMatrix(rad(90),Vector3(1.0,0.0,0.0)).applyGL();
        gllibCylinder(cano_raio,cano_altura,cano_precisao);
    glPopMatrix();
    // Parte traseira:
    glPushMatrix();
        scaleMatrix(1.0,1.0,cano_traseira_escala).applyGL();
        translationMatrix(Vector3(x,0.0,0.0)).applyGL();
        gllibSphere(cano_raio,cano_precisao);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_divisoria()
{
    double divisoria_lado = QBSG_CANO_RAIO;
    double divisoria_largura = 0.9;
    double divisoria_altura = 1.4;
    double divisoria_comprimento = 25.105;
    glPushMatrix();
        scaleMatrix(divisoria_largura,divisoria_altura,divisoria_comprimento).applyGL();
        translationMatrix(Vector3(0.0,0.02,(divisoria_lado/2.0))).applyGL();
        gllibCube(divisoria_lado);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_suporte()
{
    double suporte_lado = 0.1;
    double suporte_largura = 1.6;
    double suporte_altura = 1.5;
    double suporte_comprimento = 18.0;
    double suporte_deslocamento = -0.16;
    glPushMatrix();
        translationMatrix(Vector3(0.0,suporte_deslocamento,0.0)).applyGL();
        scaleMatrix(suporte_largura,suporte_altura,suporte_comprimento).applyGL();
        rotationMatrix(rad(90),Vector3(1.0,0.0,0.0)).applyGL();
        translationMatrix(Vector3(0.0,(suporte_lado/2.0),0.0)).applyGL();
        gllibCylinder(suporte_lado,suporte_lado,QBSG_CANO_PRECISAO);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_coronha()
{
    double coronha_raio = 0.104;
    double coronha_raio_maior = 0.15;
    double coronha_altura = 0.7;
    double coronha_precisao = QBSG_CANO_PRECISAO;

    glPushMatrix();
        translationMatrix(Vector3(0.0,-0.13,0.0)).applyGL();
        rotationMatrix(rad(-90),Vector3(1.0,0.0,0.0)).applyGL();
        shearMatrix(70).applyGL();
        scaleMatrix(1.0,1.0,1.25).applyGL();
        translationMatrix(Vector3(0.0,(coronha_altura/2.0),0.0)).applyGL();
        // Coronha arrendondada --- --- --- --- --- --- --- --- --- --- --- --- ---
        glPushMatrix();
            translationMatrix(Vector3(0.0,(coronha_altura/2.0),0.0)).applyGL();
            gllibSphere(coronha_raio,coronha_precisao);
        glPopMatrix();
        // Coronha arrendondada --- --- --- --- --- --- --- --- --- --- --- --- ---
        gllibFrustum(coronha_raio,coronha_raio_maior,coronha_altura,coronha_precisao);
    glPopMatrix();
}

// Trava que abre a parte traseira da espingarda:
void QuadBarreledShotgunRacruvido::draw_trava()
{
    double trava_raio = 0.05;
    double trava_altura = 0.05;
    double trava_comprimento = 6.0;
    glPushMatrix();
        rotationMatrix(rad(-5),Vector3(1.0,0.0,0.0)).applyGL();
        scaleMatrix(1.0,1.0,trava_comprimento).applyGL();
        translationMatrix(Vector3(0.0,(trava_altura/2.0),-trava_raio*(sqrt(3)/4.0))).applyGL();
        rotationMatrix(rad(-30),Vector3(0.0,1.0,0.0)).applyGL();
        gllibCylinder(trava_raio,trava_altura,1.5);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_gatilho(float z)
{
    double gatilho_raio_interno = 0.04;
    double gatilho_raio_externo = 0.2;
    double gatilho_rebaixamento = -0.26;
    double gatilho_click_raio = 0.04;
    // Proteção do gatilho:
    glColor3f(0.52, 0.37, 0.26);
    glPushMatrix();
        translationMatrix(Vector3(0.0,gatilho_rebaixamento,z)).applyGL();
        rotationMatrix(rad(30),Vector3(1.0,0.0,0.0)).applyGL();
        rotationMatrix(rad(90),Vector3(0.0,0.0,1.0)).applyGL();
        gllibTorus(gatilho_raio_interno,gatilho_raio_externo,2.0,3.0);
    glPopMatrix();
    // Gatilho em si:
    glColor3f(0.9,0.3,0.3);
    glPushMatrix();
        translationMatrix(Vector3(0.0,-0.33,z)).applyGL();
        shearMatrix(70).applyGL();
        scaleMatrix(1.0,3.0,1.0).applyGL();
        gllibCube(gatilho_click_raio);
    glPopMatrix();
}

// Desenha um única espingarda (na posição (x,0,z)):
void QuadBarreledShotgunRacruvido::draw_single_shotgun(float x, float z)
{
    float canos_distancia = (1.05)*QBSG_CANO_RAIO;
    glPushMatrix();
        translationMatrix(Vector3(x,0.0,z)).applyGL();

        glColor3f(0.15,0.15,0.15);
        draw_cano(-canos_distancia);

        glColor3f(0.15,0.15,0.15);
        draw_cano(canos_distancia);

        glColor3f(0.13,0.13,0.13);
        draw_divisoria();

        glColor3f(0.5, 0.50, 0.39); // Cor de madeira.
        draw_suporte();

        glColor3f(0.52, 0.37, 0.26);
        draw_coronha();

        glColor3f(0.13,0.13,0.13);
        draw_trava();

        draw_gatilho(0.15);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_cano_cisalhado(float x, float z, bool orientacao)
{
    double cano_raio = (1.4)*QBSG_CANO_RAIO;
    double cano_altura = 0.4;
    double cano_precisao = QBSG_CANO_PRECISAO;
    double angulo = 90;
    double cano_buraco_comprimento = 0.002;

    // Por padrao, gera um cano do lado esquerdo.
    // Se for "false", gera um cano do lado direito.
    if (orientacao == false)
        angulo *= -1;

    glPushMatrix();
        translationMatrix(Vector3(x,0.0,z)).applyGL();
        rotationMatrix(rad(angulo),Vector3(0.0,0.0,1.0)).applyGL();
        rotationMatrix(rad(-45),Vector3(1.0,0.0,0.0)).applyGL();
        scaleMatrix(0.70,1.0,1.0).applyGL();
        shearMatrix(45).applyGL();
        // "Buracos" nos canos:
        glColor3f(0.0, 0.0, 0.0);
        glPushMatrix();
            translationMatrix(Vector3(0.0,-cano_buraco_comprimento,0.0)).applyGL();
            gllibCylinder((0.8)*cano_raio,cano_buraco_comprimento,cano_precisao);
        glPopMatrix();
        glColor3f(0.15,0.15,0.15);
        translationMatrix(Vector3(0.0,(cano_altura/2.0),0.0)).applyGL();
        gllibCylinder(cano_raio,cano_altura,cano_precisao);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_coronha_serrada()
{
    double coronha_raio = 0.08;
    double coronha_raio_maior = 0.18;
    double coronha_altura = 1.0;
    double coronha_precisao = QBSG_CANO_PRECISAO;
    glPushMatrix();
        translationMatrix(Vector3(0.0,-0.26,-0.7)).applyGL();
        rotationMatrix(rad(90),Vector3(1.0,0.0,0.0)).applyGL();
        glPushMatrix();
            translationMatrix(Vector3(0.0,0.0,0.035)).applyGL();
            rotationMatrix(rad(-10),Vector3(1.0,0.0,0.0)).applyGL();
            scaleMatrix(1.0,1.2,1.45).applyGL();
            translationMatrix(Vector3(0.0,(coronha_altura/4.0),0.0)).applyGL();
            gllibCylinder(coronha_raio,(coronha_altura/2.0),coronha_precisao);
        glPopMatrix();
        shearMatrix(80).applyGL();
        scaleMatrix(1.0,1.0,2.0).applyGL();
        translationMatrix(Vector3(0.0,-(coronha_altura/2.0),0.0)).applyGL();
        // Canto arrendondado:
        glPushMatrix();
            translationMatrix(Vector3(0.0,(coronha_altura/2.0),0.0)).applyGL();
            gllibSphere(coronha_raio,coronha_precisao);
        glPopMatrix();
        gllibFrustum(coronha_raio,coronha_raio_maior,coronha_altura,coronha_precisao);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_parafuso(float y, float z)
{
    double parafuso_raio = 0.025;
    double parafuso_altura = 0.85;
    double parafuso_precisao = QBSG_CANO_PRECISAO;
    glPushMatrix();
        translationMatrix(Vector3(0.0,y,z)).applyGL();
        rotationMatrix(rad(90),Vector3(0.0,0.0,1.0)).applyGL();
        gllibCylinder(parafuso_raio,parafuso_altura,parafuso_precisao);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_suporte_cabo_frontal(float z)
{
    double suporte_raio_1 = 0.01;
    double suporte_raio_2 = 0.75;
    double suporte_largura = 1.0;
    double suporte_altura = 0.25;
    double suporte_comprimento = 10.0;
    glColor3f(0.5, 0.5, 0.5);
    glPushMatrix();
        translationMatrix(Vector3(0.0,0.0,z)).applyGL();
        scaleMatrix(suporte_largura,suporte_altura,suporte_comprimento).applyGL();
        rotationMatrix(rad(90),Vector3(1.0,0.0,0.0)).applyGL();
        rotationMatrix(rad(45),Vector3(0.0,1.0,0.0)).applyGL();
        gllibTorus(suporte_raio_1,suporte_raio_2,1.5,2.0);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_cabo_frontal()
{
    double cabo_lado = 0.1;
    double cabo_largura = 1.0;
    double cabo_altura = 6.0;
    double cabo_comprimento = 1.8;
    double deslocamento_Y = -0.43;
    double deslocamento_Z = 2.4;
    glPushMatrix();
        translationMatrix(Vector3(0.0,deslocamento_Y,deslocamento_Z)).applyGL();
        scaleMatrix(cabo_largura,cabo_altura,cabo_comprimento).applyGL();
        gllibCube(cabo_lado);
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw_lanterna(float y, float z)
{
    double lanterna_raio_menor = 0.14;
    double lanterna_raio_maior = 0.19;
    double lanterna_altura = 0.1;
    double lanterna_frente_altura = 0.05;
    double lanterna_comprimento = 0.9;
    double lanterna_luz_altura = 0.001;
    double lanterna_suporte = 0.8;
    double lanterna_precisao = QBSG_CANO_PRECISAO;
    glPushMatrix();
        // Todo o conjunto:
        translationMatrix(Vector3(0.0,y,z)).applyGL();
        rotationMatrix(rad(-90),Vector3(1.0,0.0,0.0)).applyGL();

        // "Luz" da lanterna:
        glColor3f(0.0,0.8,0.0);
        glPushMatrix();
            translationMatrix(Vector3(0.0,-(lanterna_luz_altura+lanterna_frente_altura+(lanterna_altura)/2.0),0.0)).applyGL();
            gllibCylinder((0.85)*lanterna_raio_maior,lanterna_luz_altura,lanterna_precisao);
        glPopMatrix();

        // Cor da lanterna:
        glColor3f(0.05,0.05,0.05);

        // Parte frontal:
        glPushMatrix();
            translationMatrix(Vector3(0.0,-(lanterna_frente_altura+lanterna_altura)/2.0,0.0)).applyGL();
            gllibCylinder(lanterna_raio_maior,lanterna_frente_altura,lanterna_precisao);
        glPopMatrix();

        // Parte central:
        gllibFrustum(lanterna_raio_menor,lanterna_raio_maior,lanterna_altura,lanterna_precisao);

        // Parte traseira:
        glPushMatrix();
            translationMatrix(Vector3(0.0,(lanterna_comprimento/2.0),0.0)).applyGL();
            gllibCylinder(lanterna_raio_menor,lanterna_comprimento,lanterna_precisao);
        glPopMatrix();

        // Suportes da lanterna:
        glColor3f(0.42, 0.27, 0.16);
        for(double i=1.1 ; i<=3.1 ; i+=2.0)
        {
            glPushMatrix();
                scaleMatrix(0.34,0.2,0.2).applyGL();
                translationMatrix(Vector3(0.0,i,-0.8)).applyGL();
                gllibCube(lanterna_suporte);
            glPopMatrix();
        }
    glPopMatrix();
}

void QuadBarreledShotgunRacruvido::draw()
{
    /// *** Duas espingardas ***
    float distancia_single_shotgun = 0.27;
    // Espingarda esquerda:
    draw_single_shotgun(distancia_single_shotgun,0.0);
    // Espingarda direita:
    draw_single_shotgun(-distancia_single_shotgun,0.0);

    /// *** Canos cisalhados ***
    float canos_cis_dist_interna = 1.1;
    float canos_cis_dist_externa = 2.925;
    float canos_cis_dist_Z = 3.25;

    // Canos cisalhados esquerdos:
    // * De dentro:
    draw_cano_cisalhado(canos_cis_dist_interna*QBSG_CANO_RAIO,canos_cis_dist_Z,true);
    // * De fora:
    draw_cano_cisalhado(canos_cis_dist_externa*canos_cis_dist_interna*QBSG_CANO_RAIO,(-1.5)*QBSG_CANO_RAIO+canos_cis_dist_Z,true);

    // Canos cisalhados direitos:
    // * De dentro:
    draw_cano_cisalhado((-1)*canos_cis_dist_interna*QBSG_CANO_RAIO,canos_cis_dist_Z,false);
    // * De fora:
    draw_cano_cisalhado((-1)*canos_cis_dist_externa*canos_cis_dist_interna*QBSG_CANO_RAIO,(-1.5)*QBSG_CANO_RAIO+canos_cis_dist_Z,false);

    /// *** Coronha central ***
    glColor3f(0.52, 0.37, 0.26);
    draw_coronha_serrada();

    /// *** Parafusos para juntar os 3 cabos ***
    glColor3f(0.647059,0.164706,0.164706);
    draw_parafuso(-0.18,-0.2);
    draw_parafuso(-0.25,-0.4);
    draw_parafuso(-0.33,-0.6);

    /// *** Cabo frontal ***
    glColor3f(0.85,0.85,0.85);
    draw_suporte_cabo_frontal(2.4);

    glColor3f(0.08,0.08,0.08);
    draw_cabo_frontal();

    /// *** Lanterna ***
    draw_lanterna(0.29,1.4);
}
